﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using FluorineFx;

namespace AMFNet
{
    /// <summary>
    /// AMF 网络通讯服务端
    /// </summary>
    public class AMFNetServer
    {
        /// <summary>
        /// 发送队列最大数。
        /// </summary>
        private const int SEND_LIST_MAX = 100;
        /// <summary>
        /// 接收队列最大长度
        /// </summary>
        private int _MaxPackegSize;
        /// <summary>
        /// 最大连接数。
        /// </summary>
        private int _MaxSocketCount;

        private TcpListener tcpLs = null;
        //已连接队列
        private List<AMFClientSocket> ClientSocketList = new List<AMFClientSocket>();
        //空闲队列
        private List<AMFClientSocket> FreeSocketList = new List<AMFClientSocket>();
        /// <summary>
        /// 断开连接事件
        /// </summary>
        public AMFNetDisonnectedCallback OnDisonnected;
        /// <summary>
        /// 接收数据事件
        /// </summary>
        public AMFNetReceiveCallback OnReceive;
        /// <summary>
        /// 连接事件
        /// </summary>
        public AMFNetConnectedCallback OnConnected;

        /// <summary>
        /// 打开服务端
        /// </summary>
        /// <param name="Ip"></param>
        /// <param name="Port"></param>
        /// <param name="MaxPackegSize">数据包最大长度</param>
        /// <param name="MaxSocketCount">最大连接数</param>
        public void OpenServer(IPAddress Ip,int Port,int MaxPackegSize,int MaxSocketCount)
        {
            _MaxPackegSize = MaxPackegSize;
            _MaxSocketCount = MaxSocketCount;
            InitFreeSocketList();
            tcpLs = new TcpListener(Ip, Port);
            tcpLs.Start();
            //开始异步监听
            try
            {
                tcpLs.BeginAcceptSocket(AcceptSocketCallback, null);
            }
            catch (Exception ex)
            {
                Console.WriteLine("监听失败：" + ex.Message);
            }
        }

        /// <summary>
        /// 关闭服务端。
        /// </summary>
        public void CloseServer()
        {
            if (tcpLs != null)
            {
                tcpLs.Stop();
            }
        }
        /// <summary>
        /// 关闭某个Socket连接。
        /// </summary>
        /// <param name="ob"></param>
        public void CloseSocket(object SocketObject)
        {
            AMFClientSocket so = (AMFClientSocket)SocketObject;
            try
            {
                
                so.ClientSocket.Close();
                so = null;
            }
            catch (Exception ex)
            {

            }
        }
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="SocketObject"></param>
        /// <param name="aMessage"></param>
        /// <returns></returns>
        public bool SendMessage(object SocketObject,MessageBase aMessage)
        {
            AMFClientSocket so = (AMFClientSocket)SocketObject;
            lock (so.SendLock)
            {
                if (so.SendList.Count >= SEND_LIST_MAX)
                {
                    return false;
                }
                //增加到发送列表中
                so.SendList.Add(aMessage);
                SendMessageFromSendList(so);
            }
            return true;
        }

        /// <summary>
        /// 从发送队列中取出发送包并发送
        /// </summary>
        /// <param name="so"></param>
        private void SendMessageFromSendList(AMFClientSocket so)
        {
            if (so.CanSend && so.SendList.Count>0)
            {
                //置为“不可发送状态”
                so.CanSend = false;
                MessageBase aMessage = so.SendList[0];
                so.SendList.RemoveAt(0);
                try
                {
                    so.SendArray.Clear();
                    so.SendArray.WriteObject(aMessage);

                    byte[] buf = so.SendArray.GetBuffer();

                    so.ClientSocket.BeginSend(buf, 0, (int)so.SendArray.Position, SocketFlags.None, SendCallback, so);
                }
                catch (Exception ex)
                {
                    //发送失败
                }
            }
        }

        /// <summary>
        /// 发送回调
        /// </summary>
        /// <param name="ar"></param>
        private void SendCallback(IAsyncResult ar)
        {
            AMFClientSocket so = (AMFClientSocket)ar.AsyncState;
            lock (so.SendLock)
            {
                so.CanSend = true;
                SendMessageFromSendList(so);
            }
        }
        /// <summary>
        /// 临听接入请求
        /// </summary>
        /// <param name="ar"></param>
        private void AcceptSocketCallback(IAsyncResult ar)
        {
            Socket clientSocket;
            try
            {
                clientSocket = tcpLs.EndAcceptSocket(ar);
            }
            catch (Exception ex)
            {
                //Console.WriteLine("监听失败：" + ex.Message);
                return;
            }

            AMFClientSocket so = GetFreeSocket();
            if (so != null)
            {
                so.ClientSocket = clientSocket;
                so.CanSend = true;
                so.ReceivePosition = 0;
                so.SendList.Clear();
                if (OnConnected != null)
                {
                    OnConnected(so);
                }
            }
            else
            {
                clientSocket.Close();
            }

            //继续接受连接
            try
            {
                tcpLs.BeginAcceptSocket(AcceptSocketCallback, null);
            }
            catch (Exception ex)
            {
                Console.WriteLine("监听失败：" + ex.Message);
            }
            //开始接收数据
            DoReceive(so);
        }

        /// <summary>
        /// 开始异步接收数据
        /// </summary>
        /// <param name="so"></param>
        private void DoReceive(AMFClientSocket so)
        {
            int BufferSize = so.ReceiveBuffer.Length - so.ReceivePosition;
            //缓冲区不足
            if (BufferSize <= 0)
                return;
            try
            {
                so.ClientSocket.BeginReceive(so.ReceiveBuffer
                    , so.ReceivePosition
                    , BufferSize
                    , SocketFlags.None
                    , ReceiveCallback
                    , so);
            }
            catch (Exception ex)
            {
                //Console.WriteLine("接收数据失败：" + ex.Message);
                CallOnDisconnected(so);

            }
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="ar"></param>
        private void ReceiveCallback(IAsyncResult ar)
        {
            AMFClientSocket so = (AMFClientSocket)ar.AsyncState;
            Socket s = so.ClientSocket;
            int read;
            try
            {
                read = s.EndReceive(ar);
            }
            catch (Exception ex)
            {
                //Console.WriteLine("接收数据失败：" + ex.Message);
                CallOnDisconnected(so);
                return;
            }
            if (read > 0)
            {
                //todo.
                //对数据时行处理
                so.ReceivePosition += read;
                HandleBuffer(so);
                //开始接收数据
                DoReceive(so);
            }
            else
            {
                CallOnDisconnected(so);
            }

        }

        /// <summary>
        /// 处理接收缓冲区
        /// </summary>
        /// <param name="so"></param>
        private void HandleBuffer(AMFClientSocket so)
        {
           
            while (so.ReceivePosition > 0)
            {
                FluorineFx.AMF3.ByteArray ba = so.FluorineFxArray;
                ba.Clear();
                try
                {
                    ba.Position = 0;
                    ba.WriteBytes(so.ReceiveBuffer, 0, so.ReceivePosition);
                    ba.Position = 0;
                    MessageBase aMessage = (MessageBase)ba.ReadObject();
                    so.ReceivePosition -= ba.Position;
                    CallOnReceive(so, aMessage);
                }
                catch (Exception ex)
                {
                    //数据错误，或者数据未完整
                    //Console.WriteLine("数据错误，或者数据未完整:" + ex.Message);
                    return;
                }
            }
        }

        /// <summary>
        /// 调用接收数据回调
        /// </summary>
        /// <param name="aMessage"></param>
        private void CallOnReceive(AMFClientSocket so,MessageBase aMessage)
        {
            if (OnReceive != null)
            {
                OnReceive(so,aMessage);
            }
        }

        /// <summary>
        /// 调用连接断开的回调函数
        /// </summary>
        /// <param name="so"></param>
        private void CallOnDisconnected(AMFClientSocket so)
        {
            try
            {
                so.ClientSocket.Close();
            }
            catch (Exception ex)
            {
            }
            AddFreeSocket(so);
            if (OnDisonnected != null)
            {
                OnDisonnected(so);
            }
        }

        /// <summary>
        /// 初始化空闲连接
        /// </summary>
        private void InitFreeSocketList()
        {
            for (int i = 0; i < _MaxSocketCount; i++)
            {
                AMFClientSocket so = new AMFClientSocket(_MaxPackegSize);
                FreeSocketList.Add(so);
            }
        }

        /// <summary>
        /// 取得一个空闲连接
        /// </summary>
        /// <returns></returns>
        private AMFClientSocket GetFreeSocket()
        {
            AMFClientSocket so = null;
            lock (FreeSocketList)
            {
                if (FreeSocketList.Count > 0)
                {
                    so = FreeSocketList[0];
                    FreeSocketList.RemoveAt(0);
                }
            }
            lock (ClientSocketList)
            {
                ClientSocketList.Add(so);
            }
            return so;
        }

        /// <summary>
        /// 回收一个空闲连接
        /// </summary>
        /// <param name="so"></param>
        private void AddFreeSocket(AMFClientSocket so)
        {
            so.SendList.Clear();
            so.FluorineFxArray.Clear();
            so.SendArray.Clear();

            lock (ClientSocketList)
            {
                ClientSocketList.Remove(so);
            }
            lock (FreeSocketList)
            {
                if (FreeSocketList.IndexOf(so) < 0)
                {
                    FreeSocketList.Add(so);
                } 
            }
        }
    }
}
